{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from mxnet import autograd, nd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[[0.]\n",
       " [1.]\n",
       " [2.]\n",
       " [3.]]\n",
       "<NDArray 4x1 @cpu(0)>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''\n",
    "简单例子，对函数 y = 2x^T * x 求关于列向量 x 的梯度\n",
    "'''\n",
    "x = nd.arange(4).reshape((4,1))\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "为了求有关变量x的梯度，我们需要先调⽤ attach_grad 函数来申请存储梯度所需要的内存\n",
    "'''\n",
    "x.attach_grad()\n",
    "with autograd.record():\n",
    "    y = 2 * nd.dot(x.T, x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[[ 0.]\n",
       " [ 4.]\n",
       " [ 8.]\n",
       " [12.]]\n",
       "<NDArray 4x1 @cpu(0)>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''\n",
    "接下来我们可以通过调⽤backward函数⾃动求梯度\n",
    "L2范数是指向量各元素的平方和然后求平方根\n",
    "'''\n",
    "y.backward()\n",
    "assert (x.grad - 4*x).norm().asscalar() == 0\n",
    "x.grad"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "'''\n",
    "训练模式和预测模式\n",
    "在平常的状态下：autograd 处在一个预测模式中\n",
    "当调用 record 函数后，在默认情况下 autograd 会将运行模式从预测模式转为训练模式\n",
    "可以通过调用 is_training 函数来查看\n",
    "在有些情况下，同⼀个模型在训练模式和预测模式下的⾏为并不相同。我们会在后⾯的章节（如\n",
    "“丢弃法” ⼀节）详细介绍这些区别\n",
    "'''\n",
    "print(autograd.is_training())\n",
    "with autograd.record():\n",
    "    print(autograd.is_training())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "'''\n",
    "对 Python 控制流求梯度\n",
    "这⾥循环（while循环）迭代的次数和条件判断（if语句）的执⾏都取决于输⼊ a 的值。\n",
    "'''\n",
    "def f(a):\n",
    "    b = a * 2\n",
    "    while b.norm().asscalar() < 1000:\n",
    "        b = b * 2\n",
    "    if b.sum().asscalar() > 0:\n",
    "        c = b\n",
    "    else:\n",
    "        c = 100 * b\n",
    "    return c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\n",
       "[1.]\n",
       "<NDArray 1 @cpu(0)>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = nd.random.normal(shape=1)\n",
    "a.attach_grad()\n",
    "with autograd.record():\n",
    "    c = f(a)\n",
    "c.backward()\n",
    "a.grad == c/a"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
